home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-04-24 | 64.9 KB | 2,186 lines | [TEXT/ALFA] |
- ## -*-Tcl-*-
- # ###################################################################
- # HTML mode - tools for editing HTML documents
- #
- # FILE: "htmlUtils.tcl"
- # created: 96-09-01 13.01.43
- # last update: 99-04-24 13.16.33
- # Author: Johan Linde
- # E-mail: <jlinde@telia.com>
- # www: <http://www.theophys.kth.se/~jl/Alpha.html>
- #
- # Version: 2.1.4
- #
- # Copyright 1996-1999 by Johan Linde
- #
- # This software may be used freely, and distributed freely, as long as the
- # receiver is not obligated in any way by receiving it.
- #
- # If you make improvements to this file, please share them!
- #
- # ###################################################################
- ##
-
- proc htmlUtils.tcl {} {}
-
- #
- # Mark file
- #
- proc HTML::parseFuncs {} {
- return [htmlMarkFile2 0]
- }
-
- proc HTML::MarkFile {} {
- htmlMarkFile2 1
- message "Marks set."
- }
-
- proc htmlMarkFile2 {markfile} {
- set pos 0
- set exp {<[Hh][1-6][^>]*>}
- set exp2 {</[Hh][1-6]>}
- while {![catch {search -s -f 1 -r 1 -m 0 -i 0 $exp $pos} rs] &&
- ![catch {search -s -f 1 -r 1 -m 0 -i 0 $exp2 [lindex $rs 1]} res]} {
- set start [lindex $rs 0]
- set end [lindex $res 1]
- set text [getText $start $end]
- # Remove tabs and returns from text.
- regsub -all "\[\t\r\]+" $text " " text
- # remove all tags from text
- set headtext [htmlTagStrip $text]
- # Set mark only on one line.
- if {$end > [nextLineStart $start]} {
- set end [expr [nextLineStart $start] - 1]
- }
-
- set indlevel [getText [expr $start + 2] [expr $start + 3]]
-
- if {$indlevel > 0 && $indlevel < 7} {
- set lab [string range " " 2 $indlevel]
- append lab $lab $indlevel " " $headtext
- # Cut the menu item if it's longer than 30 letters, not to make it too long.
- if {[string length $lab] > 30} {
- set lab "[string range $lab 0 29]…"
- }
- if {$markfile} {
- setNamedMark $lab $start $start $end
- } else {
- lappend parse $lab [lineStart $start]
- }
- }
- set pos $end
- }
- if {!$markfile} {return $parse}
- }
-
-
- #
- # return positions of tags of including elements, as a list of 5 elements --
- # openstart openend closestart closeend elementname.
- # Elements without a closing tag are ignored.
- # args: point to start search backward from; point which must be enclosed
- #
- # if any problem, return just {0}
- #
- proc htmlGetContainer {curPos inclPos} {
-
- set startPos $curPos
- set startPos2 $inclPos
- set searchFinished 0
- message "Searching for enclosing tags…"
- while {!$searchFinished} {
- # find first tag
- set isStartTag 0
- while {!$isStartTag} {
- if {[catch {search -s -f 0 -r 1 -i 0 -m 0 {<[^<>]+>} $startPos} res]} {
- message ""
- return {0}
- }
- set tag1start [lindex $res 0]
- set tag1end [lindex $res 1]
- # get element name
- if {![regexp {<([^ \t\r]+).*>} [getText $tag1start $tag1end] tmp tag]} {
- message ""
- return {0}
- }
- # is this a closing tag?
- if {[string index $tag 0] != "/"} { set isStartTag 1}
- set startPos [expr $tag1start - 1]
- }
- # find closing tag
- set res [htmlGetClosing $tag $tag1end]
-
- set tag2start [lindex $res 0]
- set tag2end [lindex $res 1]
- # If container enclosed along with us, or there is no closing tag,
- # continue searching.
- if {![llength $res] || $tag2end < $inclPos} {
- set startPos [expr $tag1start - 1]
- } else {
- set Container "$tag1start $tag1end $tag2start $tag2end"
- set searchFinished 1
- }
- }
-
- message ""
- return [concat $Container [string toupper $tag]]
- }
-
-
- #
- # return position an opening tag if the first element to the left
- # of startPos is an element with only an opening tag, as a list of 3 elements --
- # openstart openend elementname.
- #
- # if any problem, return empty string
- #
-
- proc htmlGetOpening {startPos} {
-
- while {1} {
- if {[catch {search -s -f 0 -r 1 -i 0 -m 0 {<[^<>]+>} $startPos} res]} {
- return
- }
- set tag1start [lindex $res 0]
- set tag1end [lindex $res 1]
- # get element name
- if {![regexp {<([^ \t\r]+).*>} [getText $tag1start $tag1end] tmp tag]} {
- return
- }
- # is this a closing tag?
- if {[string index $tag 0] == "/"} {return}
- # comment?
- if {[string range $tag 0 2] != "!--"} {break}
- set startPos [expr $tag1start - 1]
- }
-
- # find closing tag
- set res [htmlGetClosing $tag $tag1end]
-
- if {![llength $res] } {
- return "$tag1start $tag1end [string toupper $tag]"
- } else {
- return
- }
-
- }
-
- proc htmlGetClosing {tag sPos} {
- set x </${tag}>
- set sPos2 $sPos
- while {1} {
- set res [search -s -f 1 -r 1 -i 1 -m 0 -n $x $sPos]
- # Found any closing tag.
- if {![llength $res]} {break}
- # Look for another opening tag of the same element.
- set y "<${tag}(\[ \\t\\r\]+|>)"
- set res2 [search -s -f 1 -r 1 -i 1 -m 0 -n $y $sPos2]
- # Is it further away than the closing tag.
- if {![llength $res2] || [lindex $res2 0] > [lindex $res 0]} {break}
- # If not, find the next closing tag.
- set sPos [lindex $res 1]
- set sPos2 [lindex $res2 1]
- }
- return $res
- }
-
- # Change choice of an attribute with pre-defined choices.
- proc htmlChangeChoice {} {
- set pos [expr [getPos] - 1]
- if {[catch {search -s -f 0 -r 1 -i 0 -m 0 {<[^<>]+>} $pos} res] ||
- [lindex $res 1] < $pos ||
- ![regexp {<([^ \t\r>]+)} [eval getText $res] tmp tag] ||
- [catch {search -s -f 0 -r 1 -i 0 -m 0 {[ \t\r]+[^=]+=\"?[^\" \t\r>]*\"?} $pos} res1] ||
- [lindex $res1 1] < $pos ||
- ![regexp {([^=]+=)((\"[^\" \t\r]*\")|([^\" \t\r>]*))} [eval getText $res1] tmp attr choice]} {
- beep
- message "Current position is not at an attribute with choices."
- return
- }
- set pos0 [expr [lindex $res1 0] + [string length $attr]]
- set pos1 [expr $pos0 + [string length $choice]]
- set choice [string trim $choice \"]
- set tag [string toupper $tag]
- if {$tag == "INPUT"} {
- if {![regexp -nocase {type=(([^\" \t\r>]+)|(\"[^\" \t\r]+\"))} [eval getText $res] tmp tag]} {
- beep
- message "Current position is not at an attribute with choices."
- return
- }
- set tag [string trim [string toupper $tag] \"]
- }
- if {$tag == "LI"} {
- set ltype [htmlFindList]
- if {$ltype == "UL"} {
- set tag "LI IN UL"
- } elseif {$ltype == "OL"} {
- set tag "LI IN OL"
- }
- }
- set attr [string trim [string toupper $attr]]
- if {($tag != "OL" && $tag != "LI IN OL") || $attr != "TYPE="} {set choice [string toupper $choice]}
- set choices [htmlGetChoices $tag]
- foreach c $choices {
- if {[string match "${attr}*" $c]} {
- lappend matches [string range $c [string length $attr] end]
- }
- }
- if {![info exists matches]} {
- beep
- message "Current position is not at an attribute with choices."
- return
- }
- if {[set this [lsearch -exact $matches $choice]] < 0} {set this 0}
- incr this
- if {$this == [llength $matches]} {set this 0}
- set this [lindex $matches $this]
- if {($tag != "OL" && $tag != "LI IN OL") || $attr != "TYPE="} {set this [htmlSetCase $this]}
- replaceText $pos0 $pos1 "\"$this\""
- goto [expr ($pos0 + [string length $this] > $pos) ? $pos + 1 : $pos0 + [string length $this] + 1]
- }
-
-
- # Save current window and uploads it to the ftp server.
- proc htmlSavetoFTPServer {} {
- global htmlPasswords HTMLmodeVars ftpSig
-
- set win [stripNameCount [lindex [winNames -f] 0]]
- if {[set this [htmlThisFilePath 4]] == ""} {return}
- set home [lindex $this 3]
- if {$home == "" && [lindex $this 0] != "file:///"} {set home [htmlInWhichHomePage "[lindex $this 0][lindex $this 1]"]}
- if {$home == "" || [lindex $this 4] == "4"} {
- alertnote "Current window is not in a home page folder."
- return
- }
-
- foreach f $HTMLmodeVars(FTPservers) {
- if {[lindex $f 0] == $home} {set serv $f}
- }
- if {![info exists serv]} {
- alertnote "No ftp server specified for this home page."
- htmlHomePages "[lindex $this 0][lindex $this 1]"
- return
- }
-
- if {[lindex $serv 3] != ""} {set htmlPasswords($home) [lindex $serv 3]}
- if {![info exists htmlPasswords($home)]} {
- if {![catch {htmlGetPassword [lindex $serv 1]} pword]} {
- set htmlPasswords($home) $pword
- } else {
- return
- }
- }
- save
- set path [lindex $this 2]
- if {[lindex $serv 4] != ""} {set path [join [list [lindex $serv 4] $path] /]}
- if {![info exists ftpSig] || ![app::isRunning $ftpSig] && [catch {app::launchBack $ftpSig}]} {
- getApplSig "Please locate your ftp application" ftpSig
- app::launchBack $ftpSig
- }
- currentReplyHandler htmlHandleReply
- switch $ftpSig {
- Arch -
- FTCh {AEBuild -r -q -t 30000 '$ftpSig' Arch Stor ---- [makeAlis $win] FTPh "“[lindex $serv 1]”" FTPc "“$path”" ArGU "“[lindex $serv 2]”" ArGp "“$htmlPasswords($home)”"}
- Woof {
- set path [string range $path 0 [expr [string last / $path] - 1]]
- AEBuild -r -q -t 30000 '$ftpSig' PURL PURL ---- [makeAlis $win] dest "“ftp://[lindex $serv 2]:$htmlPasswords($home)@[lindex $serv 1]/$path”"
- }
- }
- }
-
- proc htmlHandleReply {reply} {
- global htmlPasswords
- set ans [string range $reply 11 end]
- if {[regexp {^errs:“([^”]+)”} $ans dum err]} {
- # Fetch error
- if {[regexp {Error: (.*)} $err dum err2]} {set err $err2}
- alertnote "Ftp error: $err"
- unset htmlPasswords
- } elseif {[regexp {^'----':(-?[0-9]*)} $ans dum err]} {
- if {$err != "0"} {
- # Anarchie error.
- message "Ftp error."
- unset htmlPasswords
- } else {
- message "Document uploaded to ftp server."
- }
- } elseif {$ans == "\\\}"} {
- message "Document uploaded to ftp server."
- } else {
- return 0
- }
- return 1
- }
-
-
- proc htmlGetPassword {host} {
- set values [dialog -w 300 -h 90 -t "Password for $host:" 10 20 290 30 \
- -e "" 10 40 290 42 -b OK 20 60 85 80 -b Cancel 105 60 170 80]
- if {[lindex $values 2]} {error "Cancel"}
- return [string trim [lindex $values 0]]
- }
-
- proc htmlForgetPasswords {} {
- global htmlPasswords
- message "Passwords forgotten."
- unset htmlPasswords
- }
-
- # Calculate the total size of a document including images etc.
- proc htmlDocumentSize {} {
- # Get path to this window.
- if {[set thisURL [htmlThisFilePath 3]] == ""} {return}
- set exp1 "<!--|\[ \\t\\n\\r\]+(SRC=|LOWSRC=|DYNSRC=|BACKGROUND=)(\"\[^\">\]+\"|\[^ \\t\\n\\r>\]+)"
- set exp2 {/\*|[ \t\r\n]+(url)\(\"?([^\"\)]+)\"?\)}
- set commStart1 "<!--"
- set commEnd1 "-->"
- set commStart2 {/*}
- set commEnd2 {*/}
- set size 0
- set counted {}
- set external 0
- set notfound 0
- for {set i 1} {$i < 3} {incr i} {
- set pos 0
- set exp [set exp$i]
- set commStart [set commStart$i]
- set commEnd [set commEnd$i]
- while {![catch {search -s -f 1 -i 1 -m 0 -r 1 $exp $pos} res]} {
- set restxt [eval getText $res]
- # Comment?
- if {$restxt == $commStart} {
- if {![catch {search -s -f 1 -m 0 -i 0 -r 0 -- $commEnd [lindex $res 1]} res]} {
- set pos [lindex $res 1]
- continue
- } else {
- break
- }
- }
- # Get path to link.
- regexp -nocase $exp $restxt dum1 dum2 linkTo
- set linkTo [htmlURLunEscape [string trim $linkTo \"]]
- if {![catch {lindex [htmlPathToFile [lindex $thisURL 0] [lindex $thisURL 1] [lindex $thisURL 2] [lindex $thisURL 3] $linkTo] 0} linkToPath]} {
- if {[file exists $linkToPath] && ![file isdirectory $linkToPath]} {
- if {[lsearch -exact $counted $linkToPath] < 0} {
- getFileInfo $linkToPath arr
- incr size $arr(datalen)
- lappend counted $linkToPath
- }
- } else {
- set notfound 1
- }
- } else {
- set external 1
- }
- set pos [lindex $res 1]
- }
- }
- incr size [maxPos]
- if {$size > 1000} {
- set size "[expr $size /1024] kB"
- } else {
- append size " bytes"
- }
- set txt "Total size: $size."
- if {$notfound} {append etxt "Some files not found. "}
- if {$external} {append etxt "External sources excluded."}
- if {$notfound || $external} {append txt " ([string trim $etxt])"}
- alertnote $txt
- }
-
- #
- # dividing line
- #
- proc htmlCommentLine {} {
- global HTMLmodeVars fillColumn
- set wordWrap $HTMLmodeVars(wordWrap)
- set comStr [htmlCommentStrings]
- set prefixString [lindex $comStr 0]
- set suffixString [lindex $comStr 1]
- set s "===================================================================================="
- set l [expr [string length $prefixString] + [string length $suffixString]]
- if {$wordWrap} {
- set l [expr $fillColumn - $l - 1]
- } else {
- set l [expr 75 - $l - 1]
- }
- insertText [htmlOpenCR [htmlFindNextIndent]] $prefixString [string range $s 0 $l] $suffixString "\r"
- }
-
-
- #===============================================================================
- # Character translation
- #===============================================================================
-
- #
- # Converting characters to HTML entities.
- #
- # 1 = < > &
- # 0 = áé etc.
- proc htmlCharacterstohtml {ltgtamp} {
- global htmlSpecialCharacter
- global htmlSpecialCapCharacter htmlSpecialSymbCharacter
-
- if {$ltgtamp} {
- set charlist {& < >}
- } else {
- foreach a [array names htmlSpecialCharacter] {
- if { $a != "eth" && $a != "thorn" && $a != "y´"} {
- lappend charlist $a
- }
- }
-
- foreach a [array names htmlSpecialCapCharacter] {
- if {$a != "ETH" && $a != "THORN" && $a != "Y´"} {
- lappend charlist $a
- }
- }
- lappend charlist ¡ ¿
- }
-
- set subs1 0; set lett 0
- set pos [getPos]
- if {[set start $pos] == [set end [selEnd]]} {
- if {$ltgtamp && \
- [askyesno "There is no selection. Really translate < > & in whole document?"] == "no"} {return}
- set messageString "document"
- set start 0
- set end [maxPos]
- set isDoc 1
- } else {
- set messageString "selection"
- set isDoc 0
- }
- message "Translating…"
- set text [getText $start $end]
- set tmp $text
- set upos $pos
- set st $start
- if {!$ltgtamp} {
- while {[regexp -indices -nocase {<!--[ \t\r]+#(INCLUDE|LASTMODIFIED)[ \t\r]+[^>]+>} $tmp str]} {
- set sv [string range $tmp [lindex $str 0] [lindex $str 1]]
- if {[expr $st + [lindex $str 1]] < $upos} {
- incr pos [expr 17 - [string length $sv]]
- } elseif {[expr $st + [lindex $str 0]] < $upos} {
- incr pos [expr $st + [lindex $str 0] - $upos]
- }
- lappend savestr $sv
- set tmp [string range $tmp [lindex $str 1] end]
- incr st [lindex $str 1]
- }
- regsub -all -nocase "<!--\[ \t\r\]+#(INCLUDE|LASTMODIFIED)\[ \t\r\]+\[^>\]+>" $text {<!-- #INCLUDE -->} text
- }
- if {$isDoc} {
- set text1 [string range $text 0 [expr $pos - $start - 1]]
- set text2 [string range $text [expr $pos - $start] end]
- } else {
- set text1 $text
- }
- foreach char $charlist {
-
- if {[info exists htmlSpecialCharacter($char)]} {
- set rtext "\\&$htmlSpecialCharacter($char);"
- } elseif {[info exists htmlSpecialCapCharacter($char)]} {
- set rtext "\\&$htmlSpecialCapCharacter($char);"
- } elseif {$char == "¡"} {
- set rtext "\\¡"
- } elseif {$char == "¿"} {
- set rtext "\\¿"
- } elseif {$char == ">"} {
- set rtext "\\>"
- } elseif {$char == "<"} {
- set rtext "\\<"
- } elseif {$char == "&"} {
- set rtext "\\&"
- }
-
- set subNum [regsub -all $char $text1 [set rtext] text1]
- incr subs1 [expr $subNum * ([string length $rtext] - 2)]
- incr lett $subNum
- if {$isDoc} {
- incr lett [regsub -all $char $text2 [set rtext] text2]
- }
-
- }
- set text $text1
- if {$isDoc} {append text $text2}
- if {$lett} {
- if {[info exists savestr]} {
- set i 0
- set tmp ""
- while {[regexp -indices -nocase {<!--[ \t\r]+#(INCLUDE|LASTMODIFIED)[ \t\r]+[^>]+>} $text str]} {
- append tmp [string range $text 0 [expr [lindex $str 0] - 1]]
- append tmp [lindex $savestr $i]
- set text [string range $text [expr [lindex $str 1] + 1] end]
- incr i
- }
- set text "$tmp$text"
- }
- replaceText $start $end $text
- if {$isDoc} {
- goto [expr $upos + $subs1]
- } else {
- set end [getPos]
- select $start $end
- }
- }
- message "$lett characters translated in $messageString."
- }
-
-
-
- #
- # Converting HTML entities to characters.
- #
- # 1 = < > &
- # 0 = áé etc.
- proc htmltoCharacters {ltgtamp} {
- global htmlCharacterSpecial
- global htmlCapCharacterSpecial
-
- message "Translating…"
-
- if {$ltgtamp} {
- set entitylist {"&" "<" ">"}
- } else {
- foreach a [array names htmlCharacterSpecial] {
- if { $a != "eth" && $a != "thorn" && $a != "y´"} {
- lappend entitylist "&$a;"
- }
- }
-
- foreach a [array names htmlCapCharacterSpecial] {
- if {$a != "ETH" && $a != "THORN" && $a != "Y´"} {
- lappend entitylist "&$a;"
- }
- }
- # ¡ ¿
- lappend entitylist "¡" "¿"
- }
- set subs1 0; set lett 0
- set pos [getPos]
- if {[set start $pos] == [set end [selEnd]]} {
- # Move position to linestart to make sure no letter is split.
- set pos [lineStart $pos]
- set messageString "document"
- set start 0
- set end [maxPos]
- set isDoc 1
- } else {
- set messageString "selection"
- set isDoc 0
- }
-
- set text [getText $start $end]
- set tmp $text
- set upos $pos
- set st $start
- if {!$ltgtamp} {
- while {[regexp -indices -nocase {<!--[ \t\r]+#(INCLUDE|LASTMODIFIED)[ \t\r]+[^>]+>} $tmp str]} {
- set sv [string range $tmp [lindex $str 0] [lindex $str 1]]
- if {[expr $st + [lindex $str 1]] < $upos} {
- incr pos [expr 17 - [string length $sv]]
- } elseif {[expr $st + [lindex $str 0]] < $upos} {
- incr pos [expr $st + [lindex $str 0] - $upos]
- }
- lappend savestr $sv
- set tmp [string range $tmp [lindex $str 1] end]
- incr st [lindex $str 1]
- }
- regsub -all -nocase "<!--\[ \t\r\]+#(INCLUDE|LASTMODIFIED)\[ \t\r\]+\[^>\]+>" $text {<!-- #INCLUDE -->} text
- }
- if {$isDoc} {
- set text1 [string range $text 0 [expr $pos - $start - 1]]
- set text2 [string range $text [expr $pos - $start] end]
- } else {
- set text1 $text
- }
- foreach char $entitylist {
- set schar [string range $char 1 [expr [string length $char] - 2]]
- if {[info exists htmlCharacterSpecial($schar)]} {
- set rtext "$htmlCharacterSpecial($schar)"
- } elseif {[info exists htmlCapCharacterSpecial($schar)]} {
- set rtext "$htmlCapCharacterSpecial($schar)"
- } elseif {$schar == "#161"} {
- set rtext ¡
- } elseif {$schar == "#191"} {
- set rtext ¿
- } elseif {$schar == "amp"} {
- set rtext "\\&"
- } elseif {$schar == "lt"} {
- set rtext "<"
- } elseif {$schar == "gt"} {
- set rtext ">"
- }
-
- set subNum [regsub -all $char $text1 $rtext text1]
- incr subs1 [expr $subNum * ([string length $char] - 1)]
- incr lett $subNum
- if {$isDoc} {
- incr lett [regsub -all $char $text2 $rtext text2]
- }
-
- }
- set text $text1
- if {$isDoc} {append text $text2}
- if {$lett} {
- if {[info exists savestr]} {
- set i 0
- set tmp ""
- while {[regexp -indices -nocase {<!--[ \t\r]+#(INCLUDE|LASTMODIFIED)[ \t\r]+[^>]+>} $text str]} {
- append tmp [string range $text 0 [expr [lindex $str 0] - 1]]
- append tmp [lindex $savestr $i]
- set text [string range $text [expr [lindex $str 1] + 1] end]
- incr i
- }
- set text "$tmp$text"
- }
- replaceText $start $end $text
- if {$isDoc} {
- goto [expr $upos - $subs1]
- } else {
- set end [getPos]
- select $start $end
- }
- }
- message "$lett characters translated in $messageString."
- }
-
-
- #===============================================================================
- # General Commands
- #===============================================================================
-
- # remove containing tags
- proc htmlUntagandSelect {} {htmlUntag 1}
-
- proc htmlUntag {{selectit 0}} {
- set curPos [getPos]
- set tags [htmlGetContainer $curPos [selEnd]]
- if {[llength $tags] < 5} {
- alertnote "Cannot decide on enclosing tags."
- return
- }
- # delete them
- replaceText [lindex $tags 0] [lindex $tags 3] \
- [getText [lindex $tags 1] [lindex $tags 2]]
- if {$selectit} {
- select [lindex $tags 0] \
- [expr [lindex $tags 2] - [lindex $tags 1] + [lindex $tags 0]]
- } else {
- if {$curPos < [lindex $tags 1]} {set curPos [lindex $tags 1]}
- if {$curPos > [lindex $tags 2]} {set curPos [lindex $tags 2]}
- goto [expr $curPos - [lindex $tags 1] + [lindex $tags 0]]
- }
- message "[lindex $tags 4] deleted."
- }
-
- # select container, like Balance (cmd-B)
- proc htmlSelectinContainer {} {htmlSelectContainer 1}
-
- proc htmlSelectContainer {{inside 0}} {
- set start [getPos]
- if {$start != 0 &&
- ![catch {getText $start [expr $start + 2]} lookingAt] &&
- $lookingAt != "</" &&
- [string range $lookingAt 0 0] == "<"} {
- incr start -1
- }
- set tags [htmlGetContainer $start [selEnd]]
- if {[llength $tags] == 5} {
- if {$inside} {
- select [lindex $tags 1] [lindex $tags 2]
- } else {
- select [lindex $tags 0] [lindex $tags 3]
- }
- message "[lindex $tags 4] selected."
- } else {
- beep
- message "Cannot decide on enclosing tags."
- }
- }
-
- # Select an opening tag, or remove it, of an element without a closing tag.
- proc htmlRemoveOpening {} {htmlSelectOpening 1}
-
- proc htmlSelectOpening {{remove 0}} {
- set begin [getPos]
- # back up one if possible and selection is wanted.
- if {$begin >0 && !$remove} {incr begin -1}
- set tag [htmlGetOpening $begin]
- if {[llength $tag] == 3} {
- if {$remove} {
- deleteText [lindex $tag 0] [lindex $tag 1]
- if {$begin < [lindex $tag 1]} {set begin [lindex $tag 1]}
- goto [expr $begin - [lindex $tag 1] + [lindex $tag 0]]
- message "[lindex $tag 2] deleted."
- } else {
- select [lindex $tag 0] [lindex $tag 1]
- message "[lindex $tag 2] selected."
- }
- } else {
- if {$remove} {
- alertnote "Cannot find opening tag."
- } else {
- beep
- message "Cannot find opening tag."
- }
- }
- }
-
- # Called by cmd-double-click.
- # Change attributes if click on a tag.
- proc htmlChangeDblClick {} {
- set pos [getPos]
- if {[catch {search -s -f 0 -r 1 -i 0 -m 0 {<[^<>]+>} $pos} res] ||
- [lindex $res 1] < $pos} {return}
- set txt [getText [expr [lindex $res 0] + 1] [expr [lindex $res 1] - 1]]
- if {[string index [set tag [lindex $txt 0]] 0] == "/" || $tag == "!--"} {return}
- if {[set newTag [htmlChangeElement $txt [string toupper $tag] [lindex $res 0]]] != ""} {
- replaceText [lindex $res 0] [lindex $res 1] $newTag
- }
- }
-
- # Change an existing element.
- proc htmlChangeContainer {} {
- set tag [htmlGetContainer [getPos] [selEnd]]
- if {[llength $tag] == 5} {
- set newTag [htmlChangeElement [getText [expr [lindex $tag 0] + 1] \
- [expr [lindex $tag 1] - 1]] [lindex $tag 4] [lindex $tag 0]]
- if {[string length $newTag]} {
- replaceText [lindex $tag 0] [lindex $tag 1] $newTag
- }
- } else {
- alertnote "Cannot decide on enclosing tags."
- }
- }
-
- proc htmlChangeOpening {} {
- set tag [htmlGetOpening [getPos]]
- if {[llength $tag] == 3} {
- set newTag [htmlChangeElement [getText [expr [lindex $tag 0] + 1] \
- [expr [lindex $tag 1] - 1]] [lindex $tag 2] [lindex $tag 0]]
- if {[string length $newTag]} {
- replaceText [lindex $tag 0] [lindex $tag 1] $newTag
- }
- } else {
- alertnote "Cannot find opening tag."
- }
- }
-
- #
- # Exstracts all attributes to a element from a list, and puts up a dialog window
- # where the user can change the attributes.
- #
- proc htmlChangeElement {tag elem {wrPos 0}} {
- global htmlColorAttr htmlURLAttr HTMLmodeVars
- global htmluserColorname htmlColorNumber
- global htmlElemAttrOptional1 htmlElemKeyBinding
- global htmlElemEventHandler1 htmlWindowAttr htmlPlugins
- global htmlSpecURL htmlSpecColor htmlSpecWindow
-
- # Remove tabs and returns from list.
- regsub -all "\[\t\r\]+" $tag " " tag
-
- # Remove element name.
- set tagelem [lindex $tag 0]
- set tag [string range $tag [string length $tagelem] end]
- set attrs ""
- set attrVals ""
-
- # Exstract the attributes.
- while {[regexp {[ ]+([^ "]+"[^"]*"|[^ "]+)} $tag thisatt]} {
- set tag [string range $tag [string length $thisatt] end]
- set thisatt [htmlRemoveQuotes $thisatt]
- lappend attrs [string toupper [string trim [lindex $thisatt 0]]]
- lappend attrVals [lindex $thisatt 1]
- }
-
- # All INPUT elements are defined differently. Must extract TYPE.
- if {$elem == "INPUT"} {
- set typeIndex [lsearch -exact [string toupper $attrs] "TYPE="]
- if {$typeIndex >= 0 } {
- set elem [string toupper [lindex $attrVals $typeIndex]]
- set used "INPUT TYPE=\"${elem}\""
- if {![info exists htmlElemKeyBinding($elem)]} {set elem "INPUT TYPE=$elem"}
- # Remove TYPE attribute from list.
- set attrs [lreplace $attrs $typeIndex $typeIndex]
- set attrVals [lreplace $attrVals $typeIndex $typeIndex]
- } else {
- beep
- message "INPUT element without a TYPE attribute."
- return
- }
- } else {
- set used $elem
- }
-
- # If EMBED element, choose which
- if {$elem == "EMBED"} {
- if {[catch {listpick -p "Which plug-in?" [lsort $htmlPlugins]} elem] || ![string length $elem]} {return}
- }
-
- # If LI element, check in which list.
- if {$elem == "LI"} {
- set ltype [htmlFindList]
- if {$ltype == "UL"} {
- set elem "LI IN UL"
- } elseif {$ltype == "OL"} {
- set elem "LI IN OL"
- }
- }
-
- # Element known by HTML mode?
- if {![info exists htmlElemAttrOptional1($elem)]} {
- alertnote "Unknown element: $elem"
- return
- }
-
- set useBig $HTMLmodeVars(changeInBigWindows)
- set optatts [htmlGetOptional $elem]
- set optattsUp [string toupper $optatts]
- set alloptatts [htmlGetOptional $elem 1]
- set alloptattsUp [string toupper $alloptatts]
- set reqatts [htmlGetRequired $elem]
- set allAttrs [htmlGetUsed $elem $reqatts $optatts]
- set reallyAllAtts [string toupper [concat $reqatts $alloptatts]]
-
- set choices [htmlGetChoices $elem]
- set numAttrs [htmlGetNumber $elem]
-
- set errText ""
-
- # First check if one which is normally not used is used.
- set addNotUsed 0
- set toup [string toupper $allAttrs]
- foreach a $attrs {
- if {[lsearch -exact $toup $a] < 0 && [lsearch -exact $reallyAllAtts $a] >= 0} {
- regsub -all "\[ \n\r\t]+([join $allAttrs |])" " $optatts" " " notUsedAtts
- append allAttrs " $notUsedAtts"
- set addNotUsed 1
- break
- }
- }
-
- # then check some hidden one is used
- set addHidden 0
- set toup [string toupper $allAttrs]
- foreach a $attrs {
- if {[lsearch -exact $toup $a] < 0 && [lsearch -exact $reallyAllAtts $a] >= 0} {
- regsub -all "\[ \n\r\t]+([join $optatts |])" " $alloptatts" " " hiddenAtts
- append allAttrs " $hiddenAtts"
- set addNotUsed 1
- set addHidden 1
- break
- }
- }
- # finally check if some is unknown
- set toup [string toupper $allAttrs]
- foreach a $attrs {
- if {[lsearch -exact $toup $a] < 0} {
- lappend errText "Unknown attribute: $a"
- }
- }
-
- # Add something if all attrs are hidden.
- if {![llength $allAttrs]} {
- set allAttrs $optatts
- set addNotUsed 1
- }
-
- # Does this element have any attributes?
- if {![llength $allAttrs]} {
- if {[llength $errText]} {
- if {[askyesno "$elem has no attributes. Remove the ones in the text?"] == "no"} {
- return
- } else {
- return [htmlSetCase <$elem>]
- }
- } else {
- beep
- message "$elem has no attributes."
- return
- }
- }
-
- set values ""
- # Add two dummy elements for OK and Cancel buttons.
- if {$useBig} {set values {0 0}}
- set allAttrs [string toupper $allAttrs]
- # Build a list with attribute vales.
- foreach a $allAttrs {
- set attrIndex [lsearch -exact $attrs $a]
- if {$attrIndex >= 0 } {set aval [lindex $attrVals $attrIndex]}
- set a2 [string trimright $a =]
- if {[string index $a [expr [string length $a] - 1]] != "="} {
- # Flag
- if {$attrIndex >= 0} {
- lappend values 1
- } else {
- lappend values 0
- }
- } elseif {([lsearch -exact $htmlURLAttr $a] >= 0 && [lsearch -exact $htmlSpecURL "${elem}!=$a2"] < 0) || \
- [lsearch -exact $htmlSpecURL "${elem}=$a2"] >= 0} {
- # URL
- if {$attrIndex >= 0} {
- set aval [htmlURLunEscape $aval]
- htmlAddToCache URLs $aval
- if {$useBig} {
- lappend values "" $aval 0
- } else {
- lappend values $aval
- }
- } else {
- if {$useBig} {
- lappend values "" "No value" 0
- } else {
- lappend values ""
- }
- }
- } elseif {([lsearch -exact $htmlColorAttr $a] >= 0 && [lsearch -exact $htmlSpecColor "${elem}!=$a2"] < 0) || \
- [lsearch -exact $htmlSpecColor "${elem}=$a2"] >= 0} {
- # Color
- if {$attrIndex >= 0} {
- set aval [htmlCheckColorNumber $aval]
- if {$aval == 0} {
- lappend errText "$a: Invalid color number."
- if {$useBig} {
- lappend values "" "No value" 0
- } else {
- lappend values ""
- }
- } elseif {[info exists htmluserColorname($aval)]} {
- if {$useBig} {
- lappend values "" $htmluserColorname($aval) 0
- } else {
- lappend values $htmluserColorname($aval)
- }
- } elseif {[info exists htmlColorNumber($aval)]} {
- if {$useBig} {
- lappend values "" $htmlColorNumber($aval) 0
- } else {
- lappend values $htmlColorNumber($aval)
- }
- } else {
- if {$useBig} {
- lappend values $aval "No value" 0
- } else {
- lappend values $aval
- }
- }
- } else {
- if {$useBig} {
- lappend values "" "No value" 0
- } else {
- lappend values ""
- }
- }
- } elseif {([lsearch -exact $htmlWindowAttr $a] >= 0 && [lsearch -exact $htmlSpecWindow "${elem}!=$a2"] < 0) || \
- [lsearch -exact $htmlSpecWindow "${elem}=$a2"] >= 0} {
- # Window
- if {$attrIndex >= 0} {
- htmlAddToCache windows $aval
- if {$useBig} {
- lappend values "" $aval
- } else {
- lappend values $aval
- }
- } else {
- if {$useBig} {
- lappend values "" "No value"
- } else {
- lappend values ""
- }
- }
- } elseif {[lsearch $numAttrs "${a}*"] >= 0} {
- # Number
- if {$attrIndex >= 0} {
- set numcheck [htmlCheckAttrNumber $elem $a $aval]
- if {$numcheck == 1} {
- lappend values $aval
- } else {
- lappend errText "$a: $numcheck"
- lappend values ""
- }
- } else {
- lappend values ""
- }
- } elseif {[lsearch $choices "${a}*"] >= 0} {
- # Choices
- if {$attrIndex >= 0} {
- set match ""
- if {!(($elem == "OL" || $elem == "LI IN OL") && $a == "TYPE=")} {
- set aval [string toupper $aval]
- }
- foreach w $choices {
- if {$w == "${a}${aval}"} {
- set match $aval
- }
- }
- if {[string length $match]} {
- lappend values $match
- } else {
- lappend errText "$a: Unknown choice, $aval."
- lappend values ""
- }
- } else {
- lappend values ""
- }
- } elseif {$attrIndex >= 0} {
- # Any other
- lappend values $aval
- } else {
- lappend values ""
- }
- }
- # If invalid attributes, continue?
- if {[llength $errText] && ![htmlErrorWindow "$elem not well-defined" $errText 1]} {
- return
- }
- if {$useBig} {
- set r [htmlOpenElemWindow $used $elem [posX $wrPos] $values $addNotUsed $addHidden $wrPos]
- } else {
- set r [htmlOpenElemStatusBar $used $elem [posX $wrPos] $values $addNotUsed $addHidden $wrPos]
- }
- return $r
- }
-
- # Removes all tags in a selection or the whole document.
- proc htmlRemoveTags {} {
- if {![isSelection]} {
- if {[set ync [askyesno -c "Put text without tags in a new window?"]] == "cancel"} {return}
- set txt [htmlTagStrip [getText 0 [maxPos]]]
- if {$ync == "yes"} {
- new
- insertText $txt
- } else {
- replaceText 0 [maxPos] $txt
- }
- } else {
- replaceText [getPos] [selEnd] [htmlTagStrip [getSelect]]
- }
- }
-
- # Put quotes around all attributes
- proc htmlQuoteAllAttributes {} {
- htmlScanAllTags quote
- }
-
- proc htmlTagstoLowercase {} {
- htmlScanAllTags case tolower
- }
-
- proc htmlTagstoUppercase {} {
- htmlScanAllTags case toupper
- }
-
- proc htmlScanAllTags {doWhat {upperLower ""}} {
- set pos [getPos]
- if {[isSelection]} {
- set start [getPos]
- set end [selEnd]
- } else {
- set start 0
- set end [maxPos]
- }
- set text [getText $start $end]
- while {[regexp -indices {<!--|<[^<>]+>} $text tag]} {
- append newtext [string range $text 0 [lindex $tag 0]]
- set this [string range $text [expr [lindex $tag 0] + 1] [lindex $tag 1]]
- set text [string range $text [expr [lindex $tag 1] + 1] end]
- if {$this == "!--"} {
- if {[regexp -indices -- {-->} $text commend]} {
- append newtext $this[string range $text 0 [lindex $commend 1]]
- set text [string range $text [expr [lindex $commend 1] + 1] end]
- } else {
- append newtext $text
- set text ""
- }
- } else {
- if {$doWhat == "quote"} {
- regsub -all "(\[ \t\r\]+\[^=\]+=)(\[^ >\"\t\r\]+)" $this {\1"\2"} newtag
- } else {
- regsub -all "^\[^ \t\r>]+|\[ \t\r\]+\[^ \t\r=\]+=" $this "\[string $upperLower \"&\"\]" newtag
- set newtag [subst $newtag]
- }
- append newtext $newtag
- }
- }
- append newtext $text
- replaceText $start $end $newtext
- goto $pos
-
- }
-
- # opens the manual in the browser.
- proc htmlHelp {} {
- global HOME HTMLmodeVars modifiedModeVars browserSig
- switch $HTMLmodeVars(manualStartPage) {
- 0 {set start HTMLmanual.html}
- 1 {set start text:TableOfContents.html}
- 2 {set start text:HTMLmanualFrames.html}
- }
- set path "$HTMLmodeVars(manualFolder):$start"
- if {![file exists $path]} {
- if {![catch {htmlGetDir "Locate manual"} folder]} {
- set path "$folder:$start"
- if {![file exists $path]} {
- alertnote "Folder doesn't contain the HTML manual."
- return
- }
- set HTMLmodeVars(manualFolder) $folder
- lappend modifiedModeVars {manualFolder HTMLmodeVars}
- } else {
- return
- }
- }
- htmlSendWindow $path
- if {!$HTMLmodeVars(browseInForeground)} { switchTo '$browserSig' }
- }
-
- #
- # launch a viewer and pass this window to it
- #
- proc htmlSendWindow {{path ""}} {
- global HTMLmodeVars browserSig htmlPreviCabWin
-
- if {$path == ""} {
- set path [stripNameCount [lindex [winNames -f] 0]]
-
- if {[winDirty]} {
- if {$HTMLmodeVars(saveWithoutAsking) || [set ask [askyesno -c "Save '[file tail $path]'?"]] == "yes"} {
- save
- } elseif {$ask == "cancel"} {
- return
- } elseif {![file exists $path]} {
- alertnote "Can't send window to browser."
- return
- }
- }
- # Get path again, in case it was Untitled before.
- set path [stripNameCount [lindex [winNames -f] 0]]
- }
- if {![info exists browserSig] && [catch {getFileSig [icGetPref -t 1 Helper•http]} browserSig]} {set browserSig MOSS}
- if {![app::isRunning $browserSig] && [catch {app::launchBack $browserSig}]} {
- getApplSig "Please locate your web browser" browserSig
- app::launchBack $browserSig
- }
-
- # MSIE opens the file in a new window unless an open URL event is used.
- # Cyberdog opens the text file unless an open URL event is used.
- if {$browserSig == "MSIE" || $browserSig == "dogz" || $browserSig == "iCAB"} {
- set path [htmlURLescape $path 1]
- regsub -all : $path / path
- set flgs ""
- if {$browserSig == "MSIE"} {set flgs "FLGS 1"}
- if {$browserSig == "iCAB"} {set flgs "WIND -1"}
- if {$browserSig == "iCAB" && [info exists htmlPreviCabWin] && $path == $htmlPreviCabWin} {
- AEBuild '$browserSig' core clos "----" "obj{form:indx, want:type(cwin), seld:1, from:'null'()}"
- }
- if {$browserSig == "iCAB"} {set htmlPreviCabWin $path}
- eval AEBuild '$browserSig' WWW! OURL "----" "“file:///$path”" $flgs
- } else {
- sendOpenEvent noReply '$browserSig' $path
- }
- if {$HTMLmodeVars(browseInForeground)} { switchTo '$browserSig' }
- }
-
- #===============================================================================
- # Caches
- #===============================================================================
-
-
- proc htmlCleanUpCache {cache} {
- global HTMLmodeVars
- global modifiedModeVars
-
- set URLs $HTMLmodeVars($cache)
-
- if {![llength $URLs]} {
- alertnote "No $cache are cached."
- return
- }
- set urlnumber [llength $URLs]
- set screenHeight [lindex [getMainDevice] 3]
- set maxLines [expr ($screenHeight - 160) / 20]
- set pages [expr ($urlnumber - 1) / $maxLines ]
- set thispage 0
- for {set i 0} {$i < $urlnumber} {incr i} {
- lappend URLsToSave 1
- }
- set thisbox $URLsToSave
- while {1} {
- if {$thispage < $pages} {
- set thisurlnumber $maxLines
- } else {
- set thisurlnumber [expr ($urlnumber - 1 ) % $maxLines + 1]
- }
- set height [expr 75 + $thisurlnumber * 20]
- set box "-w 440 -h $height -b OK 20 [expr $height - 30] 85 [expr $height - 10] \
- -b Cancel 100 [expr $height - 30] 165 [expr $height - 10] \
- -b {Uncheck all} 180 [expr $height - 30] 265 [expr $height - 10] \
- -t {Uncheck the $cache you want to remove} 10 10 440 30 "
- if {$thispage < $pages} {
- lappend box -b "More…" 280 [expr $height - 30] 345 [expr $height - 10]
- }
- if {$thispage > 0} {
- lappend box -b "Back…" 360 [expr $height - 30] 425 [expr $height - 10]
- }
-
- set hpos 30
- set thisURLs [lrange $URLs [expr $thispage * $maxLines] \
- [expr $thispage * $maxLines + $maxLines - 1]]
- set i 0
- foreach url $thisURLs {
- lappend box -c $url [lindex $thisbox $i] 10 $hpos 430 [expr $hpos + 15]
- incr i
- incr hpos 20
- }
- set thisbox [eval [concat dialog $box]]
- if {[lindex $thisbox 1]} {
- # cancel
- return
- } elseif {[lindex $thisbox 2]} {
- # uncheck all
- set thisbox {}
- for {set i 0} {$i < [llength $thisbox]} {incr i} {
- lappend thisbox 0
- }
- } else {
- if {$pages == 0} {
- set ll 3
- } elseif {$thispage == 0 || $thispage == $pages} {
- set ll 4
- } else {
- set ll 5
- }
- set URLsToSave [eval [concat lreplace [list $URLsToSave] [expr $thispage * $maxLines] \
- [expr $thispage * $maxLines + $maxLines - 1] [lrange $thisbox $ll end]]]
- if {[lindex $thisbox 0]} {
- # OK
- break
- } elseif {$thispage < $pages && [lindex $thisbox 3]} {
- # more
- incr thispage 1
- set thisbox [lrange $URLsToSave [expr $thispage * $maxLines] \
- [expr $thispage * $maxLines + $maxLines - 1]]
- } else {
- # back
- incr thispage -1
- set thisbox [lrange $URLsToSave [expr $thispage * $maxLines] \
- [expr $thispage * $maxLines + $maxLines - 1]]
- }
- }
- }
- set newurls {}
- for {set i 0} {$i < $urlnumber} {incr i} {
- if {[lindex $URLsToSave $i]} {
- lappend newurls [lindex $URLs $i]
- }
- }
- set HTMLmodeVars($cache) $newurls
- lappend modifiedModeVars [list $cache HTMLmodeVars]
- if {![llength $newurls]} {htmlEnable$cache off}
- }
-
- proc htmlSelScrapToURL {sel msg1 msg2} {
- set newurl [htmlURLunEscape [string trim [eval get$sel]]]
- # Convert tabs and returns.
- if {[regexp {[\t\r\n]} $newurl]} {
- alertnote "$msg1 contains tabs or returns. It will not be added to the URL cache."
- return
- }
- if {[string length $newurl]} {
- htmlAddToCache URLs $newurl
- message "$newurl added to URLs."
- } else {
- beep
- message $msg2
- }
- }
-
- proc htmlAddSelection {} {
- htmlSelScrapToURL Select Selection "No selection!"
- }
-
- proc htmlAddClipboard {} {
- htmlSelScrapToURL Scrap Clipboard "Clipboard empty!"
- }
-
- proc htmlClearCache {cache} {
- global HTMLmodeVars modifiedModeVars
- if {[askyesno "Remove all $cache from [string range $cache 0 [expr [string length $cache] - 2]] cache?"] == "yes"} {
- set HTMLmodeVars($cache) {}
- lappend modifiedModeVars [list $cache HTMLmodeVars]
- htmlEnable$cache off
- }
- }
-
- # Imports all URLs in a file to the cache.
- proc htmlImport {} {
- global HTMLmodeVars modifiedModeVars htmlURLAttr
- set urls $HTMLmodeVars(URLs)
-
- if {[catch {getfile "Import URLs from:"} fil] || ![htmlIsTextFile $fil alertnote]} {return}
- set fid [open $fil r]
- set filecont " [read $fid]"
- close $fid
- if {[llength $urls]} {
- set cl [askyesno -c "Clear URL cache before importing?"]
- if {$cl == "cancel"} {
- return
- } elseif {$cl == "yes"} {
- set urls {}
- }
- }
-
- set exp1 "\[ \\t\\n\\r\]+("
- foreach attr $htmlURLAttr {
- append exp1 "$attr|"
- }
- set exp1 [string trimright $exp1 |]
- append exp1 ")(\"\[^\">\]+\"|\[^ \\t\\n\\r>\]+)"
- set exp2 {[ \t\r\n]+(url)\(\"?([^\"\)]+)\"?\)}
- for {set i1 1} {$i1 < 3} {incr i1} {
- set fcont $filecont
- set exp [set exp$i1]
- while {[regexp -nocase -indices $exp $fcont a b url]} {
- set link [htmlURLunEscape [string trim [string range $fcont [lindex $url 0] [lindex $url 1]] \"]]
- set fcont [string range $fcont [lindex $url 1] end]
- if {[lsearch -exact $urls $link] < 0} {
- lappend urls $link
- }
- }
- }
- set HTMLmodeVars(URLs) [lsort $urls]
- lappend modifiedModeVars {URLs HTMLmodeVars}
- htmlEnableURLs [expr ([llength $HTMLmodeVars(URLs)] > 0)]
- message "URLs imported."
- }
-
- # Export URLs in cache to a file.
- proc htmlExport {} {
- global HTMLmodeVars
- if {![llength $HTMLmodeVars(URLs)]} {
- alertnote "URL cache is empty."
- return
- }
- foreach url $HTMLmodeVars(URLs) {
- lappend out "HREF=\"$url\""
- }
- if {![catch {putfile "Export URL cache to:" "URL cache"} fil]} {
- if {[file exists $fil]} {removeFile $fil}
- set fid [open $fil w]
- puts $fid [join $out "\n"]
- close $fid
- message "URLs exported."
- }
- }
-
- # Add all files in a folder to URL cache.
- proc htmlAddFolder {} {
- global HTMLmodeVars modifiedModeVars
- if {[catch {htmlGetDir "Folder to cache:"} folder]} {return}
- set path ""
- foreach hp $HTMLmodeVars(homePages) {
- if {[string match "[lindex $hp 0]:*" "$folder:"]} {
- set path [string range $folder [expr [string length [lindex $hp 0]] +1] end]
- regsub -all {:} $path {/} path
- if {[string length $path]} {append path /}
- }
- }
- set val [dialog -w 350 -h 80 -t "Path:" 10 10 60 30 -e $path 70 10 340 25 \
- -b OK 20 50 85 70 -b Cancel 110 50 175 70]
- if {[lindex $val 2]} {return}
- set path [string trim [lindex $val 0]]
- if {[string length $path]} {set path "[string trimright $path /]/"}
- set urls $HTMLmodeVars(URLs)
- if {[llength $urls]} {
- set cl [askyesno -c "Clear URL cache first?"]
- if {$cl == "cancel"} {
- return
- } elseif {$cl == "yes"} {
- set urls {}
- }
- }
-
- foreach fil [glob -nocomplain "$folder:*"] {
- set name [file tail $fil]
- if {![file isdirectory $fil] && [lsearch -exact $urls "$path$name"] < 0} {
- lappend urls "$path$name"
- }
- }
- set HTMLmodeVars(URLs) [lsort $urls]
- lappend modifiedModeVars {URLs HTMLmodeVars}
- htmlEnableURLs [expr ([llength $HTMLmodeVars(URLs)] > 0)]
- message "Files added to URL cache."
- }
-
-
- #===============================================================================
- # Footers
- #===============================================================================
-
- proc htmlFooters {} {
- global HTMLmodeVars modifiedModeVars
-
- set footers [lsort $HTMLmodeVars(footers)]
- set touchedIt 0
- set this ∞
- while {1} {
- set box "-t {Footers:} 10 10 80 30 \
- -t Path: 30 50 80 70 \
- -b OK 10 110 75 130 -b Cancel 90 110 155 130 -b New… 170 110 235 130"
- if {[llength $footers]} {
- set foot ""
- foreach f $footers {
- lappend foot [file tail $f]
- }
- append box " -m [list [concat [list $this] $foot]] 90 10 440 30"
- append box " -b Remove 250 110 315 130 -b Insert 330 110 395 130"
- foreach f $footers {
- lappend box -n [file tail $f] -t $f 90 50 440 90
- }
- } else {
- append box " -m {{None defined} {None defined}} 90 10 440 30"
- }
- set values [eval [concat dialog -w 450 -h 140 $box]]
- set this [lindex $values 3]
- if {[lindex $values 0]} {
- set HTMLmodeVars(footers) $footers
- lappend modifiedModeVars {footers HTMLmodeVars}
- return
- } elseif {[lindex $values 1]} {
- if {!$touchedIt || [askyesno "Really cancel without saving changes?"] == "yes"} {return}
- } elseif {[lindex $values 2]} {
- if {![catch {htmlNewFooter $footers} newfoot]} {
- lappend footers $newfoot
- set footers [lsort $footers]
- set this [file tail $newfoot]
- set touchedIt 1
- }
- } else {
- set i [lsearch -exact $foot $this]
- set footerFile [lindex $footers $i]
- if {[lindex $values 5]} {
- if {![catch {readFile $footerFile} footText]} {
- insertText "\r$footText\r"
- set HTMLmodeVars(footers) $footers
- lappend modifiedModeVars {footers HTMLmodeVars}
- message "$this inserted."
- return
- } else {
- alertnote "Could not read $this."
- }
- } else {
- set footers [lreplace $footers $i $i]
- set touchedIt 1
- }
- }
- }
- }
-
- # Define a file as a footer.
- proc htmlNewFooter {footers} {
- set newFooter [getfile "Select the file with the footer."]
- if {![htmlIsTextFile $newFooter alertnote]} {
- error ""
- } elseif {[lsearch -exact $footers $newFooter] < 0} {
- # Can't define two footers with the same file name.
- foreach f $footers {
- if {[file tail $f] == [file tail $newFooter]} {
- alertnote "There is already a footer with the filename\
- '[file tail $newFooter]'. Two footers with the same filename\
- cannot be defined."
- error ""
- }
- }
- return $newFooter
- } else {
- alertnote "'[file tail $newFooter]' already a footer."
- error ""
- }
- }
-
-
- #===============================================================================
- # Last modified
- #===============================================================================
-
- proc htmlLastModified {} {
- global HTMLmodeVars
- set values [dialog -w 300 -h 190 -t "Last modified tags" 40 10 200 30 \
- -e $HTMLmodeVars(lastModified) 10 40 290 55 -t "Date format" 10 70 100 90 \
- -r "Long" 1 10 95 70 115 -r "Abbreviated" 0 80 95 180 115 -r "Short" 0 190 95 250 115 \
- -c "Include weekday" 0 10 120 150 140 -c "Include time" 0 160 120 290 140 \
- -b OK 20 160 85 180 -b Cancel 110 160 175 180]
- if {[lindex $values 7]} {return}
- set lm [htmlQuote [lindex $values 0]]
- set indent [htmlFindNextIndent]
- set text "<!-- [htmlSetCase "#LASTMODIFIED TEXT"]=\"$lm\" [htmlSetCase FORM]=\""
- if {[lindex $values 1]} {append text [htmlSetCase LONG]}
- if {[lindex $values 2]} {append text [htmlSetCase ABBREV]}
- if {[lindex $values 3]} {append text [htmlSetCase SHORT]}
- if {[lindex $values 4]} {append text [htmlSetCase ",WEEKDAY"]}
- if {[lindex $values 5]} {append text [htmlSetCase ",TIME"]}
- append text "\" -->"
- set text "$text\r$indent[htmlGetLastMod $text]\r$indent<!-- [htmlSetCase /#LASTMODIFIED] -->"
- if {![catch {search -s -f 1 -r 1 -m 0 -i 1 {<!--[ \t\r]+#LASTMODIFIED[ \t\r]+[^>]+>} 0} res] &&
- ![catch {search -s -f 1 -r 1 -m 0 -i 1 {<!--[ \t\r]+/#LASTMODIFIED[ \t\r]+[^>]+>} [lindex $res 1]} res2]} {
- if {[askyesno "There are already 'last modified' tags in this document. Replace them?"] == "yes"} {
- replaceText [lindex $res 0] [lindex $res2 1] $text
- }
- } else {
- insertText [htmlOpenCR $indent 1] $text "\r$indent\r$indent"
- }
- }
-
- proc htmlUpdateLastMod {args} {
- set name [lindex $args [expr [llength $args] - 1]]
- if {[lindex [winNames -f] 0] != $name} {bringToFront $name}
- set spos 0
- while {![catch {search -s -f 1 -r 1 -m 0 -i 1 {<!--[ \t\r]+#LASTMODIFIED[ \t\r]+[^>]+>} $spos} res]} {
- if {[catch {search -s -f 1 -r 1 -m 0 -i 1 {<!--[ \t\r]+/#LASTMODIFIED[ \t\r]+[^>]+>} [lindex $res 1]} res2]} {
- alertnote "The window '[file tail $name]' contains an opening 'last modified' tag without a matching closing tag."
- return
- }
- set str [htmlGetLastMod [getText [lindex $res 0] [expr [lindex $res 1] + 1]]]
- if {$str == "0"} {
- alertnote "The window '[file tail $name]' contains invalid 'last modified' tags."
- } else {
- set indent [htmlFindIndent [lindex $res 0]]
- replaceText [lindex $res 1] [lindex $res2 0] "\r" $indent $str "\r" $indent
- }
- set spos [lindex $res2 1]
- }
- }
-
- proc htmlGetLastMod {str} {
- global htmlSpecialCharacter htmlSpecialCapCharacter
- set text ""
- set form ""
- set type ""
- if {![regexp -nocase {TEXT=\"([^\"]*)\"} $str dum text] ||
- ![regexp -nocase {FORM=\"([^\"]*)\"} $str dum form] || $form == "" ||
- ![regexp -nocase {[^,]*} $form type] ||
- [lsearch -exact [list LONG ABBREV SHORT] [string toupper $type]] < 0} {return 0}
- set text [htmlUnQuote $text]
- set day [string match "*WEEKDAY*" [string toupper $form]]
- set tid [string match "*TIME*" [string toupper $form]]
- set date [mtime [now] [string tolower $type]]
- if {!$day && [string toupper $type] != "SHORT"} {
- set date [lreplace $date 0 0 [lrange [lindex $date 0] 1 end]]
- }
- if {!$tid} {
- set date [lindex $date 0]
- } else {
- set tiden [lindex $date 1]
- regexp {^[0-9]+[^0-9]+[0-9]+} $tiden tidstr
- set tiden [lreplace $tiden 0 0 $tidstr]
- set date [lreplace $date 1 1 $tiden]
- }
- set text "$text [join $date]"
- regsub -all "&" $text "\\&" text
- regsub -all "<" $text "\\<" text
- regsub -all ">" $text "\\>" text
- regsub -all "¿" $text "\\¿" text
- regsub -all "¡" $text "\\¡" text
- foreach c [array names htmlSpecialCharacter] {
- regsub -all $c $text "\\&$htmlSpecialCharacter($c);" text
- }
- foreach c [array names htmlSpecialCapCharacter] {
- regsub -all $c $text "\\&$htmlSpecialCapCharacter($c);" text
- }
- foreach c [list eth ETH thorn THORN] {
- regsub -all "&$c;" $text $c text
- }
- return $text
- }
-
- #===============================================================================
- # Home page windows
- #===============================================================================
-
- proc htmlOpenHPwin {{folder ""}} {
- global htmlHomePageWinList
- # Get folder to open.
- if {$folder == "" && [catch {htmlGetDir "Open:"} folder]} {return}
- set tail [file tail $folder]
- # Is their already a window for this folder?
- foreach win $htmlHomePageWinList {
- if {[lindex $win 0] == $folder} {
- bringToFront [lindex $win 1]
- return
- }
- }
- if {[catch {glob $folder:*} fileList]} {beep; message "Empty folder."; return}
-
- set text "$folder\rcmd-shift-C to copy URL\r"
- foreach fil $fileList {
- append text [file tail $fil] \r
- }
- if {[set winsize [htmlGetHPwinSize $folder]] == ""} {
- new -n $tail -m Home
- } else {
- eval new -n [list "$tail"] -g $winsize -m Home
- }
- insertText $text
- if {$winsize == ""} {shrinkWindow 1}
- # make folders boldface
- for {set i 0} {$i < [llength $fileList]} {incr i} {
- set fil [lindex $fileList $i]
- if {[file isdirectory $fil]} {
- insertColorEscape [rowColToPos [expr $i + 3] 0] bold
- insertColorEscape [rowColToPos [expr $i + 4] 0] 12
- }
- }
- htmlSetWin
- lappend htmlHomePageWinList [list $folder [lindex [winNames] 0]]
- }
-
- # Reads a saved home page window size.
- proc htmlGetHPwinSize {folder} {
- global PREFS htmlHPwinPositions
- if {[info exists htmlHPwinPositions($folder)]} {return $htmlHPwinPositions($folder)}
- if {![file exists "$PREFS:HTML:Home page window positions"]} {return}
- set cid [scancontext create]
- set pos ""
- scanmatch $cid "^\{?$folder\[ \}\]" {
- if {[lindex $matchInfo(line) 0] == $folder} {set pos [lrange $matchInfo(line) 1 end]}
- }
- set fid [open "$PREFS:HTML:Home page window positions"]
- scanfile $cid $fid
- close $fid
- scancontext delete $cid
- return $pos
- }
-
- proc htmlQuitHook {} {
- global PREFS htmlHPwinPositions
- if {![info exists htmlHPwinPositions]} {return}
- message "Saving home page window positions…"
- set current ""
- if {[file exists "$PREFS:HTML:Home page window positions"] &&
- ![catch {open "$PREFS:HTML:Home page window positions"} fid]} {
- set current [split [read -nonewline $fid] \n]
- close $fid
- }
- foreach c $current {
- if {[info exists htmlHPwinPositions([lindex $c 0])]} {
- append n [lrange $c 0 0] " " $htmlHPwinPositions([lindex $c 0]) \n
- unset htmlHPwinPositions([lindex $c 0])
- } else {
- append n $c \n
- }
- }
- foreach c [array names htmlHPwinPositions] {
- append n [list $c] " " $htmlHPwinPositions($c) \n
- }
- if {![catch {open "$PREFS:HTML:Home page window positions" w} fid]} {
- puts -nonewline $fid $n
- close $fid
- }
- }
-
-
- # Quick search in home page windows just like in Finder windows.
- proc htmlSearchInHPwin {char} {
- global homeTime hpWinString
- set t [ticks]
- if {[expr $t - $homeTime] > 60} {set hpWinString ""}
- append hpWinString $char
- set homeTime $t
- if {[catch {search -s -f 1 -m 0 -r 1 -i 1 "^$hpWinString" [nextLineStart [nextLineStart 0]]} res]} {return}
- select [lindex $res 0] [nextLineStart [lindex $res 1]]
- }
-
- proc htmlHomeReturn {} {
- global htmlHomePageWinList HTMLmodeVars
- foreach win $htmlHomePageWinList {
- if {[lindex [winNames] 0] == [lindex $win 1]} {
- set f [htmlGetAhpLine]
- if {![file exists $f]} {alertnote "[file tail $f] not found."; return}
- if {[file isdirectory $f]} {
- htmlOpenHPwin $f
- } else {
- getFileInfo $f a
- if {$a(type) == "TEXT"} {
- edit -c $f
- } elseif {$HTMLmodeVars(homeOpenNonTextFile)} {
- if {$a(type) == "APPL"} {
- launch -f $f
- } elseif {$a(creator) == "MACS"} {
- beep; message "Cannot open."
- } else {
- launchDoc $f
- }
- } else {
- beep; message "Not a text file."
- }
- }
- return
- }
- }
- }
-
- proc htmlHpWinBack {} {
- global htmlHomePageWinList
- foreach win $htmlHomePageWinList {
- if {[lindex [winNames] 0] == [lindex $win 1]} {
- set folder [file dirname [getText 0 [expr [nextLineStart 0] - 1]]]
- if {$folder != ""} {htmlOpenHPwin $folder}
- return
- }
- }
- }
-
- proc htmlGetAhpLine {} {
- return "[getText 0 [expr [nextLineStart 0] - 1]]:[getText [lineStart [getPos]] [expr [nextLineStart [getPos]] - 1]]"
- }
-
- # Refreshes a Home page window.
- proc htmlRefreshHpWin {{hpwin ""}} {
- global htmlHomePageWinList
- if {$hpwin == ""} {
- foreach win $htmlHomePageWinList {
- if {[lindex [winNames] 0] == [lindex $win 1]} {
- set hpwin $win
- }
- }
- }
- set curSel [file tail [htmlGetAhpLine]]
- set folder [lindex $hpwin 0]
- setWinInfo read-only 0
- if {![file exists ${folder}:] || [catch {glob $folder:*} files]} {killWindow; return}
- set len [llength $files]
- set pos [nextLineStart [nextLineStart 0]]
- set ind 0
- while {$pos < [maxPos] && $ind < $len} {
- set f [file tail [lindex $files $ind]]
- set t [string trim [getText $pos [nextLineStart $pos]]]
- while {$pos < [maxPos] && $ind < $len && $t == $f} {
- incr ind
- set pos [nextLineStart $pos]
- set f [file tail [lindex $files $ind]]
- set t [string trim [getText $pos [nextLineStart $pos]]]
- }
- if {[string compare [string tolower $t] [string tolower $f]] == 1} {
- goto $pos
- insertText $f \r
- if {[file isdirectory [lindex $files $ind]]} {
- insertColorEscape $pos bold
- if {![file isdirectory [lindex $files [expr $ind + 1]]]} {
- insertColorEscape [nextLineStart $pos] 12
- }
- } elseif {[file isdirectory [lindex $files [expr $ind + 1]]]} {
- insertColorEscape $pos 12
- insertColorEscape [nextLineStart $pos] bold
- }
- set pos [nextLineStart $pos]
- incr ind
- } else {
- deleteText $pos [nextLineStart $pos]
- }
- if {$pos < [maxPos]} {set t [string trim [getText $pos [nextLineStart $pos]]]}
- set f [file tail [lindex $files $ind]]
- }
- if {$pos < [maxPos]} {
- deleteText [expr $pos - 1] [maxPos]
- } else {
- goto [maxPos]
- foreach f [lrange $files $ind end] {
- insertText [file tail $f] \r
- if {[file isdirectory $f]} {
- insertColorEscape $pos bold
- insertColorEscape [nextLineStart $pos] 12
- }
- set pos [nextLineStart $pos]
- }
- }
- refresh
- setWinInfo dirty 0
- setWinInfo read-only 1
- beginningOfBuffer
- if {![catch {search -s -f 1 -m 0 -r 1 -- "^$curSel" 0} res]} {
- select [lindex $res 0] [nextLineStart [lindex $res 1]]
- }
- }
-
- proc htmlRefreshWindows {} {
- global htmlHomePageWinList
- set frontWin [lindex [winNames -f] 0]
- foreach win $htmlHomePageWinList {
- bringToFront [lindex $win 1]
- htmlRefreshHpWin $win
- }
- bringToFront $frontWin
- }
-
- # Copies an URL from a home page window.
- proc htmlCopyURL {} {
- global htmlHomePageWinList htmlHomePageWinURL
- foreach win $htmlHomePageWinList {
- if {[lindex [winNames] 0] == [lindex $win 1]} {
- set htmlHomePageWinURL [htmlGetAhpLine]
- message "$htmlHomePageWinURL copied."
- }
- }
- }
-
- # Pastes a previously copied URL from a home page window.
- proc htmlPasteURL {} {
- global htmlHomePageWinURL htmlIsSel htmlCurSel HTMLmodeVars elecStopMarker
- if {![info exists htmlHomePageWinURL]} {message "No URL to paste."; return}
- if {[set link [htmlGetFile 0 $htmlHomePageWinURL 2]] == ""} {return}
- set url [htmlURLescape2 [lindex $link 0]]
- htmlGetSel
- set absPos [getPos]
- set htmlWrapPos [posX [getPos]]
- if {[llength [set wh [lindex $link 1]]]} {
- set text [htmlSetCase <IMG]
- append text [htmlWrapTag "[htmlSetCase SRC=]\"$url\""]
- append text [htmlWrapTag [htmlSetCase "WIDTH=\"[lindex $wh 0]\""]]
- append text [htmlWrapTag [htmlSetCase "HEIGHT=\"[lindex $wh 1]\">"]]
- set closing ""
- } else {
- set text "<[htmlSetCase A]"
- append text [htmlWrapTag [htmlSetCase HREF=]\"$url\">]
- set closing [htmlCloseElem A]
- if {!$htmlIsSel && $HTMLmodeVars(useTabMarks)} {append closing $elecStopMarker}
- }
- append text $htmlCurSel
- set currpos [expr [getPos] + [string length $text]]
- append text $closing
- if {$htmlIsSel} { deleteSelection }
- insertText $text
- if {!$htmlIsSel} {
- goto $currpos
- }
- }
-
-
- # closeHook
- proc htmlCloseHook {name} {
- global htmlHomePageWinList
- set tmp ""
- foreach win $htmlHomePageWinList {
- if {$name != [lindex $win 1]} {
- lappend tmp $win
- }
- }
- set htmlHomePageWinList $tmp
- }
-
- # deactivateHook
- proc htmldeactivateHook {name} {
- global htmlHPwinPositions
- set winSize [getGeometry]
- # When closing size is {0 0 0 0}
- if {$winSize == {0 0 0 0}} {return}
- set htmlHPwinPositions([string trim [getText 0 [nextLineStart 0]]]) $winSize
- }
-
- namespace eval Home {}
- proc Home::DblClick {from to} {htmlHomeReturn}
-
- foreach __char {a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 . _ -} {
- bind '$__char' "htmlSearchInHPwin $__char" Home
- }
- unset __char
-
- bind '\r' htmlHomeReturn Home
- bind down <c> htmlHomeReturn Home
- bind enter htmlHomeReturn Home
- bind down downBrowse Home
- bind up upBrowse Home
- bind '\r' <c> htmlHpWinBack Home
- bind enter <c> htmlHpWinBack Home
- bind up <c> htmlHpWinBack Home
- bind 'r' <c> htmlRefreshHpWin Home
- bind 'c' <cs> htmlCopyURL Home
-
-
- #===============================================================================
- # Validation
- #===============================================================================
-
- proc htmlFindUnbalancedTags {} {
- global tileLeft tileTop tileWidth errorHeight
-
- message "Searching for unbalanced tags…"
- set fil [stripNameCount [lindex [winNames -f] 0]]
- # These may not have an closing tag.
- set empty {!DOCTYPE BASEFONT BR AREA LINK IMG PARAM HR INPUT ISINDEX BASE META}
- lappend empty COL FRAME SPACER WBR EMBED BGSOUND KEYGEN
- # These have an optional closing tag.
- set closingOptional {P DT DD LI OPTION TR TD TH HEAD BODY HTML WINDOW}
- lappend closingOptional COLGROUP THEAD TBODY TFOOT
- # These have an optional opening tag.
- set openingOptional {HTML HEAD BODY}
- lappend openingOptional TBODY
-
- set tagStack WINDOW
- set pos 0
- while {![catch {search -s -f 1 -r 1 -i 1 -m 0 {<!--|<[^<>]+>} $pos} res]} {
- set tagstart [lindex $res 0]
- set tagend [lindex $res 1]
- set tagtxt [getText $tagstart $tagend]
- if {$tagtxt == "<!--"} {
- # Comment
- if {![catch {search -s -f 1 -r 0 -m 0 -- {-->} $tagstart} res]} {
- set pos [lindex $res 1]
- } else {
- set pos [maxPos]
- }
- continue
- }
- # get element name
- if {![regexp {<[ \t\r]*([^ \t\r]+).*>} $tagtxt tmp tag]} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Empty <>.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- set pos $tagend
- continue
- }
- set tag [string toupper $tag]
- # is this a closing tag?
- if {[string index $tag 0] == "/"} {
- set tag [string range $tag 1 end]
- if {[lsearch -exact $empty $tag] >= 0} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: $tag may mot have a closing tag.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- } elseif {[lsearch -exact $tagStack $tag] < 0 && [lsearch -exact $openingOptional $tag] < 0} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Closing $tag without a matching opening tag.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- } else {
- for {set i 0} {$i < [llength $tagStack]} {incr i} {
- if {[set this [lindex $tagStack $i]] != $tag} {
- if {[lsearch -exact $closingOptional $this] < 0} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: $this must be closed before $tag.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- } else {
- break
- }
- }
- set tagStack [lrange $tagStack [expr $i + 1 ] end]
- }
- } else {
- # opening tag
- if {[lsearch -exact $empty $tag] < 0} {
- set tagStack [concat $tag $tagStack]
- }
- }
- set pos $tagend
- }
- # check if there are unclosed tags.
- for {set i 0} {$i < [llength $tagStack]} {incr i} {
- if {[lsearch -exact $closingOptional [set this [lindex $tagStack $i]]] < 0} {
- append errtxt "Line [lindex [posToRowCol [maxPos]] 0] : $this must be closed before HTML.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- }
- if {[info exists errtxt]} {
- new -n "* Errors *" -g $tileLeft $tileTop $tileWidth $errorHeight -m Brws
- insertText "Errors: (<uparrow> and <downarrow> to browse, <return> to go to file)\r\r"
- insertText $errtxt
- htmlSetWin
- } else {
- alertnote "No unbalanced tags found!"
- }
-
- }
-
- proc htmlCheckTags {} {
- global tileLeft tileTop tileWidth errorHeight
-
- message "Checking tags…"
- set fil [stripNameCount [lindex [winNames -f] 0]]
-
- htmlCheckConfig
-
- set doctype [htmlFindDoctype]
- # Remove some things depending on the doctype.
- if {$doctype == "transitional" || $doctype == "strict"} {
- regsub "FRAME" $empty "" empty
- unset mayContain(FRAMESET)
- }
- if {$doctype == "strict"} {
- foreach xxx {APPLET FONT CENTER DIR MENU STRIKE S U} {
- unset mayContain($xxx)
- }
- regsub -all "BASEFONT|ISINDEX" $empty "" empty
- }
- if {$doctype == "frameset"} {
- set mayContain(HTML) {HEAD FRAMESET}
- }
-
- # Validate
- set headHasBeen 0
- set bodyHasBeen 0
- set htmlHasBeen 0
- set tagStack WINDOW
- set currentTag WINDOW
- set pos 0
- while {![catch {search -s -f 1 -r 1 -i 1 -m 0 {<!--|<[^<>]+>} $pos} res]} {
- set tagstart [lindex $res 0]
- set tagend [lindex $res 1]
- set tagtxt [getText $tagstart $tagend]
- # get element name
- if {$tagtxt != "!--" && ![regexp {<[ \t\r]*([^ \t\r>]+)} $tagtxt tmp tag]} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Empty <>.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- set pos $tagend
- continue
- } else {
- set tag [string toupper $tag]
- }
- if {$tagstart > $pos} {
- set prevTxt [getText $pos [expr $tagstart -1]]
- } else {
- set prevTxt ""
- }
- # check for unmatched < or > in text.
- if {[regexp {<} $prevTxt]} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Unmatched <.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- if {[regexp {>} $prevTxt]} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Unmatched >.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
-
- # check for text if current element may not contain text.
- set back 0
- if {[lsearch -exact $mayContain($currentTag) text] < 0 &&
- ![regexp {^[ \t\r]*$} $prevTxt ]} {
- # back up and insert BODY if needed
- if {!$bodyHasBeen && [lsearch -exact $tagStack BODY] < 0 &&
- [lsearch -exact $tagStack FRAMESET] < 0} {
- set tagend $pos
- set tag BODY
- set back 1
- } else {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: $currentTag may not contain text.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- }
- if {!$back && $tagtxt == "<!--"} {
- # Comment
- if {![catch {search -s -f 1 -r 0 -m 0 -- {-->} $tagstart} res]} {
- set pos [lindex $res 1]
- } else {
- set pos [maxPos]
- }
- continue
- }
- # Silently ignore !DOCTYPE
- if {$tag == "!DOCTYPE"} {
- set pos $tagend
- continue
- }
- # back up and insert HEAD if needed.
- if {!$headHasBeen && [lsearch -exact $mayContain(HEAD) $tag] >= 0} {
- set tagend $pos
- set tag HEAD
- }
- # back up and insert TBODY if needed
- if {$currentTag == "TABLE" && [lsearch -exact $mayContain(TABLE) $tag] < 0} {
- set tagend $pos
- set tag TBODY
- }
- set xtag [string trimleft $tag /]
- # insert BODY if tag can't be in HEAD or HEAD is closed.
- if {!$bodyHasBeen && ([lsearch -exact $mayContain(HEAD) $xtag] < 0 ||
- [lsearch -exact $tagStack HEAD] < 0) &&
- $xtag != "HTML" && $xtag != "HEAD" && $xtag != "BODY" &&
- !($xtag == "FRAMESET" || [lsearch -exact $tagStack FRAMESET] >= 0)} {
- set tagend $pos
- set tag BODY
- }
- # insert HTML if not done
- if {!$htmlHasBeen && $tag != "HTML"} {
- set tagend $pos
- set tag HTML
- }
-
- # check if there's anything after </HTML>
- if {$tag == "/HTML"} {
- if {![regexp {^([ \t\r\n]*|([ \t\r\n]*<!--[^>]*-->)*[ \t\r\n]*)$} [getText $tagend [maxPos]]]} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Text after </HTML>.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- break
- }
- # is this a closing tag?
- if {[string index $tag 0] == "/"} {
- set tag [string range $tag 1 end]
- if {![info exists mayContain($tag)]} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: $tag is unknown.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- } else {
- if {$tag == "HEAD" || $tag == "BODY"} {set headHasBeen 1}
- if {$tag == "BODY"} {set bodyHasBeen 1}
- if {[lsearch -exact $empty $tag] >= 0} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: $tag may mot have a closing tag.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- } elseif {[lsearch -exact $tagStack $tag] < 0} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Closing $tag without a matching opening tag.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- } else {
- for {set i 0} {$i < [llength $tagStack]} {incr i} {
- if {[set this [lindex $tagStack $i]] != $tag} {
- if {[lsearch -exact $closingOptional $this] < 0} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: $this must be closed before $tag.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- } else {
- break
- }
- }
- set tagStack [lrange $tagStack [expr $i + 1 ] end]
- set currentTag [lindex $tagStack 0]
- }
- }
- } else {
- # opening tag
- if {$headHasBeen && $tag == "HEAD"} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Multiple HEAD tags.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- if {$bodyHasBeen && $tag == "BODY" && !($currentTag == "NOFRAMES" && $doctype == "frameset")} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Multiple BODY tags.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- if {$htmlHasBeen && $tag == "HTML"} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: Multiple HTML tags.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- if {$tag == "HEAD" || $tag == "BODY"} {set headHasBeen 1}
- if {$tag == "BODY"} {set bodyHasBeen 1}
- if {$tag == "HTML"} {set htmlHasBeen 1}
- # unknown tag?
- if {[set em [lsearch -exact $empty $tag]] < 0 && ![info exists mayContain($tag)]} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: $tag is unknown.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- } else {
- # implicitely close those which may not contain $tag.
- for {set i 0} {$i < [llength $tagStack]} {incr i} {
- set this [lindex $tagStack $i]
- if {[lsearch -exact $mayContain($this) $tag] < 0} {
- # Silently close those with an optional closing tag except BODY and HTML.
- if {[lsearch -exact $closingOptional $this] < 0 || $this == "BODY" || $this == "HTML"} {
- append errtxt "Line [lindex [posToRowCol $tagstart] 0]: $this may not contain $tag.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- break
- }
- } else {
- break
- }
- }
- if {$em < 0} {
- set tagStack [concat $tag [lrange $tagStack $i end]]
- set currentTag $tag
- } else {
- set tagStack [lrange $tagStack $i end]
- }
- }
- }
- set pos $tagend
- }
- # check if there are unclosed tags.
- for {set i 0} {$i < [llength $tagStack]} {incr i} {
- if {[lsearch -exact $closingOptional [set this [lindex $tagStack $i]]] < 0} {
- append errtxt "Line [lindex [posToRowCol [maxPos]] 0] : $this must be closed before HTML.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$fil\r"
- }
- }
- if {[info exists errtxt]} {
- new -n "* Errors *" -g $tileLeft $tileTop $tileWidth $errorHeight -m Brws
- insertText "Errors: (<uparrow> and <downarrow> to browse, <return> to go to line)\r\r"
- insertText $errtxt
- htmlSetWin
- } else {
- alertnote "No syntax errors found! (Attributes have not been checked.)"
- }
- }
-